//
//  BaseModel.m
//  RainbowFM
//
//  Created by Kratos on 14/12/9.
//  Copyright (c) 2014年 RB. All rights reserved.
//

#import "BaseModel.h"
#import <objc/runtime.h>

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T') {
            return (const char *)[[NSData dataWithBytes:(attribute + 3) length:strlen(attribute) - 4] bytes];
        }
    }
    return "@";
}

@implementation BaseModel
-(id)initWithDataDic:(NSDictionary*)data{
    if (self = [super init]) {
        [self setAttributes:data];
    }
    return self;
}

//属性名和json中key的对应，防止关键字直接使用，如id
//key为属性，value为json的key
//建立property和json key的映射
//此方法需要子类重写
-(NSDictionary*)attributeMapDictionary{
    return nil;
}

/**
 *  自定义描述，append到description后面
 *
 *  @return
 */
- (NSString *)customDescription{
    return nil;
}

-(SEL)getSetterSelWithAttibuteName:(NSString*)attributeName{
    NSString *capital = [[attributeName substringToIndex:1] uppercaseString];
    NSString *setterSelStr = [NSString stringWithFormat:@"set%@%@:",capital,[attributeName substringFromIndex:1]];
    return NSSelectorFromString(setterSelStr);
}


- (NSString *)description{
    NSMutableString *attrsDesc = [NSMutableString stringWithCapacity:100];
    NSDictionary *attrMapDic = [self attributeMapDictionary];
    NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
    id attributeName;
    
    while ((attributeName = [keyEnum nextObject])) {
        SEL getSel = NSSelectorFromString(attributeName);
        if ([self respondsToSelector:getSel]) {
            NSMethodSignature *signature = nil;
            signature = [self methodSignatureForSelector:getSel];
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
            [invocation setTarget:self];
            [invocation setSelector:getSel];
            NSObject *valueObj = nil;
            [invocation invoke];
            [invocation getReturnValue:&valueObj];
            if (valueObj) {
                [attrsDesc appendFormat:@" [%@=%@] ",attributeName, valueObj];
            }else {
                [attrsDesc appendFormat:@" [%@=nil] ",attributeName];
            }
            
        }
    }
    
    NSString *customDesc = [self customDescription];
    NSString *desc;
    
    if (customDesc && [customDesc length] > 0 ) {
        desc = [NSString stringWithFormat:@"%@:{%@,%@}",[self class],attrsDesc,customDesc];
    }else {
        desc = [NSString stringWithFormat:@"%@:{%@}",[self class],attrsDesc];
    }
    
    return desc;
}
-(void)setAttributes:(NSDictionary*)dataDic{
    NSDictionary *attrMapDic = [self attributeMapDictionary];
    if (attrMapDic == nil) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:[dataDic count]];
        for (NSString *key in dataDic) {
            [dic setValue:key forKey:key];
        }
        attrMapDic = dic;
    }
    NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
    id attributeName;
    while ((attributeName = [keyEnum nextObject])) {
        SEL sel = [self getSetterSelWithAttibuteName:attributeName];
        if ([self respondsToSelector:sel]) {
            NSString *dataDicKey = [attrMapDic objectForKey:attributeName];
            id attributeValue = [dataDic objectForKey:dataDicKey];
            if (![attributeValue isKindOfClass:[NSNull class]]) {
                [self performSelector:sel withObject:attributeValue];
            }
        }
    }
}

-(NSMutableDictionary*)updateAttributes:(NSDictionary*)newAttributesDic
{
    NSMutableDictionary * returnDic = [NSMutableDictionary dictionary];
    
    NSDictionary *attrMapDic = [self attributeMapDictionary];
    
    NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithCapacity:[newAttributesDic count]];
    for (NSString *key in [newAttributesDic allKeys]) {
        if ([[attrMapDic allValues] containsObject:key]) {
            [dic setValue:key forKey:[attrMapDic keyForObject:key]];
        } else {
            [dic setValue:key forKey:key];
        }
    }
    attrMapDic = dic;
    
    NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
    id attributeName;
    while ((attributeName = [keyEnum nextObject])) {
        SEL sel = [self getSetterSelWithAttibuteName:attributeName];
        if ([self respondsToSelector:sel]) {
            NSString *dataDicKey = [attrMapDic objectForKey:attributeName];
            id attributeValue = [newAttributesDic objectForKey:dataDicKey];
            //            [self performSelectorOnMainThread:sel
            //                                   withObject:attributeValue
            //                                waitUntilDone:[NSThread isMainThread]];
            [self performSelector:sel withObject:attributeValue];
            
            [returnDic setObject:attributeValue forKey:attributeName];
        }
    }
    
    return [returnDic count] > 0 ? returnDic : nil;
}

-(NSMutableDictionary*)getDictionaryByAttributes
{
    NSMutableDictionary * attrDic = [NSMutableDictionary dictionary];
    NSDictionary * attrMapDic = [self attributeMapDictionary];
    
    NSArray * keyArray = [attrMapDic allKeys];
    
    unsigned int outCount;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    
    for (int i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];
        const char *propName = property_getName(property);
        if (propName) {
            const char * propType = getPropertyType(property);
            
            NSString * propAttr = [NSString stringWithCString:propName encoding:[NSString defaultCStringEncoding]];
            NSString * propAttrType = [NSString stringWithCString:propType encoding:[NSString defaultCStringEncoding]];
            
            if ([keyArray containsObject:propAttr]) {
                //                NSString * selString = [NSString stringWithFormat:@"get%@%@", [[propAttr substringToIndex:1] uppercaseString], [propAttr substringFromIndex:1]];
                SEL getSEL = NSSelectorFromString(propAttr);
                
                if ([self respondsToSelector:getSEL]) {
                    IMP imp = [self methodForSelector:getSEL];
                    
                    id(*test)(id ,SEL) = (void*)imp;
                    id impResult = test(self, getSEL);
                    
                    if (impResult) {
                        [attrDic setObject:impResult forKey:attrMapDic[propAttr]];
                    }
                }
            }
        }
    }
    
    return attrDic;
}

- (id)initWithCoder:(NSCoder *)decoder{
    if( self = [super init] ){
        NSDictionary *attrMapDic = [self attributeMapDictionary];
        if (attrMapDic == nil) {
            return self;
        }
        NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
        id attributeName;
        while ((attributeName = [keyEnum nextObject])) {
            SEL sel = [self getSetterSelWithAttibuteName:attributeName];
            if ([self respondsToSelector:sel]) {
                id obj = [decoder decodeObjectForKey:attributeName];
                [self performSelectorOnMainThread:sel
                                       withObject:obj
                                    waitUntilDone:[NSThread isMainThread]];
            }
        }
    }
    return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder{
    NSDictionary *attrMapDic = [self attributeMapDictionary];
    if (attrMapDic == nil) {
        return;
    }
    NSEnumerator *keyEnum = [attrMapDic keyEnumerator];
    id attributeName;
    while ((attributeName = [keyEnum nextObject])) {
        SEL getSel = NSSelectorFromString(attributeName);
        if ([self respondsToSelector:getSel]) {
            NSMethodSignature *signature = nil;
            signature = [self methodSignatureForSelector:getSel];
            NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
            [invocation setTarget:self];
            [invocation setSelector:getSel];
            NSObject *valueObj = nil;
            [invocation invoke];
            [invocation getReturnValue:&valueObj];
            if (valueObj) {
                [encoder encodeObject:valueObj forKey:attributeName];
            }
        }
    }
}
- (NSData*)getArchivedData{
    return [NSKeyedArchiver archivedDataWithRootObject:self];
}

- (NSString *)cleanString:(NSString *)str {
    if (str == nil) {
        return @"";
    }
    NSMutableString *cleanString = [NSMutableString stringWithString:str];
    [cleanString replaceOccurrencesOfString:@"\n" withString:@""
                                    options:NSCaseInsensitiveSearch
                                      range:NSMakeRange(0, [cleanString length])];
    [cleanString replaceOccurrencesOfString:@"\r" withString:@""
                                    options:NSCaseInsensitiveSearch
                                      range:NSMakeRange(0, [cleanString length])];
    return cleanString;
}

@end